/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002-2006
* Sleepycat Software. All rights reserved.
*
* $Id: FileHeader.java,v 1.1 2006/05/06 08:59:55 ckaestne Exp $
*/
package com.sleepycat.je.log;
import java.nio.ByteBuffer;
import java.sql.Timestamp;
import java.util.Calendar;
import com.sleepycat.je.DatabaseException;
/**
* A FileHeader embodies the header information at the beginning of each log
* file.
*/
public class FileHeader implements LoggableObject, LogReadable {
/*
* Version 3 is to add main and dupe tree fanout values for DatabaseImpl.
* See [12328].
* Also added in Version 3 is IN LSN array compression. See [12557].
* Also added in Version 3 is a change to FileSummaryLNs: obsolete offset
* tracking was added and multiple records are stored for a single file
* rather than a single record. Each record contains the offsets that were
* tracked since the last record was written. See [11597].
* Also added in Version 3 is the full obsolete LSN in LNLogEntry.
*/
private static final int LOG_VERSION = 3;
/*
* fileNum is the number of file, starting at 0. An unsigned int, so stored
* in a long in memory, but in 4 bytes on disk
*/
private long fileNum;
private long lastEntryInPrevFileOffset;
private Timestamp time;
private int logVersion;
FileHeader(long fileNum, long lastEntryInPrevFileOffset) {
this.fileNum = fileNum;
this.lastEntryInPrevFileOffset = lastEntryInPrevFileOffset;
Calendar now = Calendar.getInstance();
time = new Timestamp(now.getTimeInMillis());
logVersion = LOG_VERSION;
}
/**
* For logging only.
*/
public FileHeader() {
}
/**
* @return whether the file header has an old version number.
*
* @throws DatabaseException if the header isn't valid.
*/
boolean validate(String fileName, long expectedFileNum)
throws DatabaseException {
if (fileNum != expectedFileNum) {
throw new LogException
("Wrong filenum in header for file " +
fileName + " expected " +
expectedFileNum + " got " + fileNum);
}
return logVersion < LOG_VERSION;
}
/**
* @return the offset of the last entry in the previous file.
*/
long getLastEntryInPrevFileOffset() {
return lastEntryInPrevFileOffset;
}
/*
* Logging support
*/
/**
* @see LoggableObject#getLogType
*/
public LogEntryType getLogType() {
return LogEntryType.LOG_FILE_HEADER;
}
/**
* @see LoggableObject#marshallOutsideWriteLatch
* Can be marshalled outside the log write latch.
*/
public boolean marshallOutsideWriteLatch() {
return true;
}
/**
* @see LoggableObject#countAsObsoleteWhenLogged
*/
public boolean countAsObsoleteWhenLogged() {
return false;
}
/**
* @see LoggableObject#postLogWork
*/
public void postLogWork(long justLoggedLsn)
throws DatabaseException {
}
/**
* A header is always a known size.
*/
static int entrySize() {
return
LogUtils.getTimestampLogSize() + // time
LogUtils.UNSIGNED_INT_BYTES + // file number
LogUtils.LONG_BYTES + // lastEntryInPrevFileOffset
LogUtils.INT_BYTES; // logVersion
}
/**
* @see LoggableObject#getLogSize
* @return number of bytes used to store this object
*/
public int getLogSize() {
return entrySize();
}
/**
* @see LoggableObject#writeToLog
* Serialize this object into the buffer. Update cksum with all
* the bytes used by this object
* @param logBuffer is the destination buffer
*/
public void writeToLog(ByteBuffer logBuffer) {
LogUtils.writeTimestamp(logBuffer, time);
LogUtils.writeUnsignedInt(logBuffer,fileNum);
LogUtils.writeLong(logBuffer, lastEntryInPrevFileOffset);
LogUtils.writeInt(logBuffer, logVersion);
}
/**
* @see LogReadable#readFromLog
* Initialize this object from the data in itemBuf.
* @param itemBuf the source buffer
*/
public void readFromLog(ByteBuffer logBuffer, byte entryTypeVersion)
throws LogException {
time = LogUtils.readTimestamp(logBuffer);
fileNum = LogUtils.getUnsignedInt(logBuffer);
lastEntryInPrevFileOffset = LogUtils.readLong(logBuffer);
logVersion = LogUtils.readInt(logBuffer);
if (logVersion > LOG_VERSION) {
throw new LogException("Expected log version " + LOG_VERSION +
" or earlier but found " + logVersion +
" -- this version is not supported.");
}
}
/**
* @see LogReadable#dumpLog
* @param sb destination string buffer
* @param verbose if true, dump the full, verbose version
*/
public void dumpLog(StringBuffer sb, boolean verbose) {
sb.append("<FileHeader num=\"0x");
sb.append(Long.toHexString(fileNum));
sb.append("\" lastEntryInPrevFileOffset=\"0x");
sb.append(Long.toHexString(lastEntryInPrevFileOffset));
sb.append("\" logVersion=\"0x");
sb.append(Integer.toHexString(logVersion));
sb.append("\" time=\"").append(time);
sb.append("\"/>");
}
/**
* @see LogReadable#logEntryIsTransactional
*/
public boolean logEntryIsTransactional() {
return false;
}
/**
* @see LogReadable#getTransactionId
*/
public long getTransactionId() {
return 0;
}
/**
* Print in xml format
*/
public String toString() {
StringBuffer sb = new StringBuffer();
dumpLog(sb, true);
return sb.toString();
}
}